#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
化学反应验证器
Chemical Reaction Validator

功能：
1. 验证化学反应的有效性（质量守恒、电荷守恒）
2. 能耗分析和优化
3. 物理科学平衡验证
4. 经济性评估
"""

import re
import logging
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass
from enum import Enum

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class ValidationStatus(Enum):
    """验证状态"""
    VALID = "有效"
    INVALID = "无效"
    WARNING = "警告"
    OPTIMIZABLE = "可优化"


@dataclass
class ValidationResult:
    """验证结果"""
    status: ValidationStatus
    message: str
    details: Dict
    score: float  # 0-100分


@dataclass
class EnergyAnalysis:
    """能耗分析"""
    heating_energy: float  # kWh
    cooling_energy: float  # kWh
    mechanical_energy: float  # kWh
    total_energy: float  # kWh
    energy_efficiency: float  # 0-1
    energy_cost: float  # CNY
    optimization_suggestions: List[str]


@dataclass
class EconomicAnalysis:
    """经济性分析"""
    raw_material_cost: float  # CNY
    energy_cost: float  # CNY
    labor_cost: float  # CNY
    equipment_depreciation: float  # CNY
    total_cost: float  # CNY
    product_value: float  # CNY
    profit: float  # CNY
    profit_margin: float  # 0-1
    roi: float  # 投资回报率
    payback_period: float  # years
    economic_feasibility: str  # 经济可行性评级


class ReactionValidator:
    """化学反应验证器"""
    
    # 元素原子量
    ATOMIC_WEIGHTS = {
        'H': 1.008, 'C': 12.011, 'N': 14.007, 'O': 15.999,
        'S': 32.065, 'P': 30.974, 'Cl': 35.453, 'Br': 79.904,
        'F': 18.998, 'I': 126.904, 'Na': 22.990, 'K': 39.098,
        'Ca': 40.078, 'Mg': 24.305, 'Fe': 55.845, 'Cu': 63.546,
        'Zn': 65.38, 'Al': 26.982, 'Si': 28.085, 'Ag': 107.868,
        'Au': 196.967, 'Pt': 195.084, 'Ni': 58.693, 'Mn': 54.938
    }
    
    # 能耗基准（kWh/kg产品）
    ENERGY_BENCHMARKS = {
        '加热': {'low': 0.5, 'medium': 1.5, 'high': 3.0},
        '冷却': {'low': 0.3, 'medium': 1.0, 'high': 2.0},
        '搅拌': {'low': 0.1, 'medium': 0.3, 'high': 0.5},
        '蒸馏': {'low': 2.0, 'medium': 4.0, 'high': 6.0},
        '干燥': {'low': 1.0, 'medium': 2.5, 'high': 4.0}
    }
    
    def __init__(self):
        """初始化验证器"""
        logger.info("化学反应验证器已初始化")
    
    def validate_reaction(self, equation: str, thermodynamics: Dict = None,
                         conditions: Dict = None) -> ValidationResult:
        """
        验证化学反应的有效性
        
        Args:
            equation: 化学反应方程式
            thermodynamics: 热力学数据
            conditions: 反应条件
        
        Returns:
            ValidationResult: 验证结果
        """
        logger.info(f"开始验证反应: {equation}")
        
        details = {}
        issues = []
        warnings = []
        score = 100.0
        
        # 1. 质量守恒验证
        mass_balance = self._validate_mass_balance(equation)
        details['mass_balance'] = mass_balance
        if not mass_balance['balanced']:
            issues.append(f"质量不守恒: {mass_balance['message']}")
            score -= 50
        
        # 2. 电荷守恒验证
        charge_balance = self._validate_charge_balance(equation)
        details['charge_balance'] = charge_balance
        if not charge_balance['balanced']:
            issues.append(f"电荷不守恒: {charge_balance['message']}")
            score -= 30
        
        # 3. 热力学可行性验证
        if thermodynamics:
            thermo_check = self._validate_thermodynamics(thermodynamics)
            details['thermodynamics'] = thermo_check
            if not thermo_check['feasible']:
                warnings.append(f"热力学警告: {thermo_check['message']}")
                score -= 10
        
        # 4. 反应条件合理性验证
        if conditions:
            conditions_check = self._validate_conditions(conditions)
            details['conditions'] = conditions_check
            if not conditions_check['reasonable']:
                warnings.append(f"条件警告: {conditions_check['message']}")
                score -= 5
        
        # 确定状态
        if issues:
            status = ValidationStatus.INVALID
            message = "; ".join(issues)
        elif warnings:
            status = ValidationStatus.WARNING
            message = "; ".join(warnings)
        else:
            status = ValidationStatus.VALID
            message = "反应有效，符合所有验证规则"
        
        return ValidationResult(
            status=status,
            message=message,
            details=details,
            score=max(0, score)
        )
    
    def _validate_mass_balance(self, equation: str) -> Dict:
        """验证质量守恒"""
        try:
            # 分离反应物和产物
            if '→' in equation:
                reactants_str, products_str = equation.split('→')
            elif '->' in equation:
                reactants_str, products_str = equation.split('->')
            elif '=' in equation:
                reactants_str, products_str = equation.split('=')
            else:
                return {'balanced': False, 'message': '无法解析方程式'}
            
            # 计算元素组成
            reactants_elements = self._count_elements(reactants_str)
            products_elements = self._count_elements(products_str)
            
            # 比较
            all_elements = set(reactants_elements.keys()) | set(products_elements.keys())
            
            unbalanced = []
            for element in all_elements:
                r_count = reactants_elements.get(element, 0)
                p_count = products_elements.get(element, 0)
                if abs(r_count - p_count) > 0.01:  # 允许小误差
                    unbalanced.append(f"{element}: 反应物{r_count} ≠ 产物{p_count}")
            
            if unbalanced:
                return {
                    'balanced': False,
                    'message': ', '.join(unbalanced),
                    'reactants': reactants_elements,
                    'products': products_elements
                }
            else:
                return {
                    'balanced': True,
                    'message': '质量守恒',
                    'reactants': reactants_elements,
                    'products': products_elements
                }
        
        except Exception as e:
            return {'balanced': False, 'message': f'验证失败: {str(e)}'}
    
    def _count_elements(self, formula_str: str) -> Dict[str, float]:
        """统计化学式中的元素数量"""
        elements = {}
        
        # 分离各个化合物
        compounds = re.split(r'\s*\+\s*', formula_str.strip())
        
        for compound in compounds:
            # 提取系数
            match = re.match(r'^(\d*\.?\d*)\s*(.+)$', compound.strip())
            if match:
                coef_str, formula = match.groups()
                coefficient = float(coef_str) if coef_str else 1.0
            else:
                coefficient = 1.0
                formula = compound.strip()
            
            # 移除相态标记
            formula = re.sub(r'\([slgaq]+\)', '', formula)
            
            # 解析化学式
            element_counts = self._parse_formula(formula)
            
            # 累加
            for element, count in element_counts.items():
                elements[element] = elements.get(element, 0) + count * coefficient
        
        return elements
    
    def _parse_formula(self, formula: str) -> Dict[str, int]:
        """解析化学式"""
        elements = {}
        
        # 匹配元素和数量
        pattern = r'([A-Z][a-z]?)(\d*)'
        matches = re.findall(pattern, formula)
        
        for element, count_str in matches:
            count = int(count_str) if count_str else 1
            elements[element] = elements.get(element, 0) + count
        
        return elements
    
    def _validate_charge_balance(self, equation: str) -> Dict:
        """验证电荷守恒"""
        try:
            # 提取离子电荷
            reactants_charge = self._count_charges(equation.split('→')[0] if '→' in equation else equation.split('->')[0])
            products_charge = self._count_charges(equation.split('→')[1] if '→' in equation else equation.split('->')[1])
            
            if abs(reactants_charge - products_charge) < 0.01:
                return {
                    'balanced': True,
                    'message': '电荷守恒',
                    'reactants_charge': reactants_charge,
                    'products_charge': products_charge
                }
            else:
                return {
                    'balanced': False,
                    'message': f'反应物电荷{reactants_charge} ≠ 产物电荷{products_charge}',
                    'reactants_charge': reactants_charge,
                    'products_charge': products_charge
                }
        
        except Exception as e:
            return {'balanced': True, 'message': '无离子，跳过电荷验证'}
    
    def _count_charges(self, formula_str: str) -> float:
        """统计电荷"""
        total_charge = 0
        
        # 匹配离子电荷 (如 Fe2+, OH-, SO4^2-)
        pattern = r'(\d*\.?\d*)\s*([A-Za-z0-9]+)(\d*)([+-])'
        matches = re.findall(pattern, formula_str)
        
        for coef, ion, charge_num, charge_sign in matches:
            coefficient = float(coef) if coef else 1.0
            charge = int(charge_num) if charge_num else 1
            if charge_sign == '-':
                charge = -charge
            total_charge += coefficient * charge
        
        return total_charge
    
    def _validate_thermodynamics(self, thermodynamics: Dict) -> Dict:
        """验证热力学可行性"""
        delta_G = thermodynamics.get('delta_G', 0)
        delta_H = thermodynamics.get('delta_H', 0)
        temperature = thermodynamics.get('temperature', 298.15)
        
        issues = []
        
        # 检查自发性
        if delta_G > 0:
            issues.append(f"ΔG={delta_G} kJ/mol > 0，反应不自发")
        
        # 检查温度合理性
        if temperature < 0 or temperature > 2000:
            issues.append(f"温度{temperature}K不合理")
        
        # 检查能量数值合理性
        if abs(delta_H) > 1000:
            issues.append(f"ΔH={delta_H} kJ/mol过大，请核实")
        
        return {
            'feasible': len(issues) == 0,
            'message': '; '.join(issues) if issues else '热力学可行',
            'is_spontaneous': delta_G < 0,
            'is_exothermic': delta_H < 0
        }
    
    def _validate_conditions(self, conditions: Dict) -> Dict:
        """验证反应条件合理性"""
        issues = []
        
        temperature = conditions.get('temperature', 298.15)
        pressure = conditions.get('pressure', 101.325)
        
        # 温度范围检查
        if temperature < 200 or temperature > 1500:
            issues.append(f"温度{temperature}K可能不合理")
        
        # 压力范围检查
        if pressure < 1 or pressure > 50000:
            issues.append(f"压力{pressure}kPa可能不合理")
        
        return {
            'reasonable': len(issues) == 0,
            'message': '; '.join(issues) if issues else '条件合理'
        }
    
    def analyze_energy(self, reaction_data: Dict, production_scale: float = 100) -> EnergyAnalysis:
        """
        能耗分析
        
        Args:
            reaction_data: 反应数据
            production_scale: 生产规模 (kg)
        
        Returns:
            EnergyAnalysis: 能耗分析结果
        """
        logger.info(f"开始能耗分析，生产规模: {production_scale} kg")
        
        conditions = reaction_data.get('conditions', {})
        thermodynamics = reaction_data.get('thermodynamics', {})
        
        # 计算各项能耗
        heating_energy = self._calculate_heating_energy(
            conditions.get('temperature', 298.15),
            production_scale,
            thermodynamics.get('delta_H', 0)
        )
        
        cooling_energy = self._calculate_cooling_energy(
            conditions.get('temperature', 298.15),
            production_scale
        )
        
        mechanical_energy = self._calculate_mechanical_energy(
            conditions.get('stirring_speed', 0),
            conditions.get('reaction_time', 60),
            production_scale
        )
        
        total_energy = heating_energy + cooling_energy + mechanical_energy
        
        # 计算能效
        theoretical_energy = abs(thermodynamics.get('delta_H', 0)) * production_scale / 100
        energy_efficiency = min(1.0, theoretical_energy / total_energy) if total_energy > 0 else 0
        
        # 计算能耗成本
        electricity_price = reaction_data.get('electricity_price', 0.8)  # CNY/kWh
        energy_cost = total_energy * electricity_price
        
        # 优化建议
        suggestions = self._generate_energy_optimization_suggestions(
            heating_energy, cooling_energy, mechanical_energy, energy_efficiency
        )
        
        return EnergyAnalysis(
            heating_energy=heating_energy,
            cooling_energy=cooling_energy,
            mechanical_energy=mechanical_energy,
            total_energy=total_energy,
            energy_efficiency=energy_efficiency,
            energy_cost=energy_cost,
            optimization_suggestions=suggestions
        )
    
    def _calculate_heating_energy(self, temperature: float, scale: float, delta_H: float) -> float:
        """计算加热能耗"""
        # 简化模型：基于温度和规模
        base_energy = (temperature - 298.15) / 100 * scale * 0.5  # kWh
        
        # 如果是吸热反应，增加能耗
        if delta_H > 0:
            base_energy += abs(delta_H) * scale / 3600  # kJ转kWh
        
        return max(0, base_energy)
    
    def _calculate_cooling_energy(self, temperature: float, scale: float) -> float:
        """计算冷却能耗"""
        # 如果反应温度高，需要冷却
        if temperature > 350:
            return (temperature - 298.15) / 100 * scale * 0.3
        return 0
    
    def _calculate_mechanical_energy(self, stirring_speed: float, time: float, scale: float) -> float:
        """计算机械能耗"""
        if stirring_speed > 0:
            # 功率估算：基于搅拌速度和规模
            power = stirring_speed / 100 * scale / 100  # kW
            return power * time / 60  # kWh
        return 0
    
    def _generate_energy_optimization_suggestions(self, heating: float, cooling: float,
                                                  mechanical: float, efficiency: float) -> List[str]:
        """生成能耗优化建议"""
        suggestions = []
        
        if efficiency < 0.5:
            suggestions.append("能效较低，建议优化反应条件或增加保温措施")
        
        if heating > 50:
            suggestions.append("加热能耗高，建议考虑热回收或使用更高效的加热方式")
        
        if cooling > 30:
            suggestions.append("冷却能耗高，建议安装热交换器回收热量")
        
        if mechanical > 10:
            suggestions.append("机械能耗高，建议优化搅拌参数或使用变频电机")
        
        if not suggestions:
            suggestions.append("能耗水平合理，继续保持")

        return suggestions

    def analyze_economics(self, reaction_data: Dict, production_scale: float = 100,
                         energy_analysis: EnergyAnalysis = None) -> EconomicAnalysis:
        """
        经济性分析

        Args:
            reaction_data: 反应数据
            production_scale: 生产规模 (kg)
            energy_analysis: 能耗分析结果

        Returns:
            EconomicAnalysis: 经济性分析结果
        """
        logger.info(f"开始经济性分析，生产规模: {production_scale} kg")

        # 1. 原料成本
        raw_material_cost = self._calculate_raw_material_cost(
            reaction_data.get('reactants', []),
            reaction_data.get('reactant_masses', {}),
            reaction_data.get('reactant_prices', {})
        )

        # 2. 能耗成本
        if energy_analysis:
            energy_cost = energy_analysis.energy_cost
        else:
            energy_cost = reaction_data.get('energy_cost', 0)

        # 3. 人工成本
        labor_cost = reaction_data.get('labor_cost', 500)  # CNY

        # 4. 设备折旧
        equipment_depreciation = reaction_data.get('equipment_depreciation', 200)  # CNY

        # 5. 总成本
        total_cost = raw_material_cost + energy_cost + labor_cost + equipment_depreciation

        # 6. 产品价值
        product_value = self._calculate_product_value(
            reaction_data.get('products', []),
            reaction_data.get('product_amounts', {}),
            reaction_data.get('product_prices', {}),
            reaction_data.get('yield_factor', 0.85)
        )

        # 7. 利润
        profit = product_value - total_cost
        profit_margin = profit / product_value if product_value > 0 else 0

        # 8. 投资回报率
        equipment_investment = reaction_data.get('equipment_investment', 100000)  # CNY
        annual_batches = reaction_data.get('annual_batches', 300)
        annual_profit = profit * annual_batches
        roi = annual_profit / equipment_investment if equipment_investment > 0 else 0

        # 9. 投资回收期
        payback_period = equipment_investment / annual_profit if annual_profit > 0 else float('inf')

        # 10. 经济可行性评级
        feasibility = self._evaluate_economic_feasibility(profit_margin, roi, payback_period)

        return EconomicAnalysis(
            raw_material_cost=raw_material_cost,
            energy_cost=energy_cost,
            labor_cost=labor_cost,
            equipment_depreciation=equipment_depreciation,
            total_cost=total_cost,
            product_value=product_value,
            profit=profit,
            profit_margin=profit_margin,
            roi=roi,
            payback_period=payback_period,
            economic_feasibility=feasibility
        )

    def _calculate_raw_material_cost(self, reactants: List, masses: Dict, prices: Dict) -> float:
        """计算原料成本"""
        total_cost = 0
        for reactant in reactants:
            formula = reactant.get('formula', '')
            mass = masses.get(formula, 0)
            price = prices.get(formula, 10)  # 默认10 CNY/kg
            total_cost += mass * price
        return total_cost

    def _calculate_product_value(self, products: List, amounts: Dict, prices: Dict, yield_factor: float) -> float:
        """计算产品价值"""
        total_value = 0
        for product in products:
            formula = product.get('formula', '')
            amount = amounts.get(formula, 0) * yield_factor
            price = prices.get(formula, 50)  # 默认50 CNY/kg
            total_value += amount * price
        return total_value

    def _evaluate_economic_feasibility(self, profit_margin: float, roi: float, payback_period: float) -> str:
        """评估经济可行性"""
        score = 0

        # 利润率评分
        if profit_margin > 0.4:
            score += 40
        elif profit_margin > 0.25:
            score += 30
        elif profit_margin > 0.15:
            score += 20
        elif profit_margin > 0:
            score += 10

        # ROI评分
        if roi > 0.5:
            score += 40
        elif roi > 0.3:
            score += 30
        elif roi > 0.15:
            score += 20
        elif roi > 0:
            score += 10

        # 回收期评分
        if payback_period < 2:
            score += 20
        elif payback_period < 3:
            score += 15
        elif payback_period < 5:
            score += 10
        elif payback_period < 10:
            score += 5

        # 评级
        if score >= 80:
            return "A级 - 经济性优秀"
        elif score >= 60:
            return "B级 - 经济性良好"
        elif score >= 40:
            return "C级 - 经济性一般"
        elif score >= 20:
            return "D级 - 经济性较差"
        else:
            return "E级 - 经济性不可行"

    def comprehensive_evaluation(self, equation: str, reaction_data: Dict,
                                production_scale: float = 100) -> Dict:
        """
        综合评估

        Args:
            equation: 化学反应方程式
            reaction_data: 反应数据
            production_scale: 生产规模

        Returns:
            Dict: 综合评估结果
        """
        logger.info("=" * 80)
        logger.info("开始综合评估")
        logger.info("=" * 80)

        # 1. 反应有效性验证
        validation = self.validate_reaction(
            equation,
            reaction_data.get('thermodynamics'),
            reaction_data.get('conditions')
        )

        # 2. 能耗分析
        energy_analysis = self.analyze_energy(reaction_data, production_scale)

        # 3. 经济性分析
        economic_analysis = self.analyze_economics(reaction_data, production_scale, energy_analysis)

        # 4. 综合评分
        overall_score = self._calculate_overall_score(
            validation.score,
            energy_analysis.energy_efficiency,
            economic_analysis.profit_margin
        )

        # 5. 综合建议
        recommendations = self._generate_recommendations(
            validation,
            energy_analysis,
            economic_analysis
        )

        return {
            'validation': validation,
            'energy_analysis': energy_analysis,
            'economic_analysis': economic_analysis,
            'overall_score': overall_score,
            'recommendations': recommendations,
            'summary': self._generate_summary(validation, energy_analysis, economic_analysis, overall_score)
        }

    def _calculate_overall_score(self, validation_score: float, energy_efficiency: float,
                                 profit_margin: float) -> float:
        """计算综合评分"""
        # 权重：验证40%，能效30%，经济性30%
        score = (
            validation_score * 0.4 +
            energy_efficiency * 100 * 0.3 +
            max(0, min(100, profit_margin * 200)) * 0.3
        )
        return round(score, 2)

    def _generate_recommendations(self, validation: ValidationResult,
                                  energy: EnergyAnalysis,
                                  economics: EconomicAnalysis) -> List[str]:
        """生成综合建议"""
        recommendations = []

        # 验证建议
        if validation.status == ValidationStatus.INVALID:
            recommendations.append("⚠️ 反应无效，必须修正化学方程式")
        elif validation.status == ValidationStatus.WARNING:
            recommendations.append("⚡ 反应存在警告，建议优化反应条件")

        # 能耗建议
        if energy.energy_efficiency < 0.5:
            recommendations.append("🔋 能效偏低，优先考虑节能措施")
        recommendations.extend([f"💡 {s}" for s in energy.optimization_suggestions[:2]])

        # 经济性建议
        if economics.profit_margin < 0:
            recommendations.append("💰 利润为负，不建议投产")
        elif economics.profit_margin < 0.15:
            recommendations.append("📊 利润率偏低，建议优化成本或提高售价")

        if economics.payback_period > 5:
            recommendations.append("⏰ 投资回收期过长，建议重新评估")

        return recommendations

    def _generate_summary(self, validation: ValidationResult, energy: EnergyAnalysis,
                         economics: EconomicAnalysis, overall_score: float) -> str:
        """生成评估摘要"""
        summary = f"""
╔════════════════════════════════════════════════════════════════════════════╗
║                          化学反应综合评估报告                              ║
╚════════════════════════════════════════════════════════════════════════════╝

【综合评分】: {overall_score}/100

【反应有效性】: {validation.status.value} (得分: {validation.score}/100)
  - {validation.message}

【能耗分析】:
  - 总能耗: {energy.total_energy:.2f} kWh
  - 能效: {energy.energy_efficiency*100:.1f}%
  - 能耗成本: ¥{energy.energy_cost:.2f}

【经济性分析】:
  - 总成本: ¥{economics.total_cost:.2f}
  - 产品价值: ¥{economics.product_value:.2f}
  - 利润: ¥{economics.profit:.2f}
  - 利润率: {economics.profit_margin*100:.1f}%
  - ROI: {economics.roi*100:.1f}%
  - 回收期: {economics.payback_period:.2f} 年
  - 可行性: {economics.economic_feasibility}

【综合评级】:
"""
        if overall_score >= 80:
            summary += "  ⭐⭐⭐⭐⭐ 优秀 - 强烈推荐实施\n"
        elif overall_score >= 70:
            summary += "  ⭐⭐⭐⭐ 良好 - 推荐实施\n"
        elif overall_score >= 60:
            summary += "  ⭐⭐⭐ 一般 - 可以考虑实施\n"
        elif overall_score >= 50:
            summary += "  ⭐⭐ 较差 - 需要优化后实施\n"
        else:
            summary += "  ⭐ 不合格 - 不建议实施\n"

        summary += "\n" + "=" * 80 + "\n"

        return summary


def main():
    """测试函数"""
    validator = ReactionValidator()

    # 测试案例：甲烷燃烧
    equation = "CH4 + 2O2 → CO2 + 2H2O"

    reaction_data = {
        'thermodynamics': {
            'delta_H': -890.3,
            'delta_G': -818.0,
            'delta_S': -242.8,
            'temperature': 298.15
        },
        'conditions': {
            'temperature': 298.15,
            'pressure': 101.325,
            'stirring_speed': 0,
            'reaction_time': 60
        },
        'reactants': [
            {'formula': 'CH4'},
            {'formula': 'O2'}
        ],
        'products': [
            {'formula': 'CO2'},
            {'formula': 'H2O'}
        ],
        'reactant_masses': {'CH4': 10.0, 'O2': 40.0},
        'reactant_prices': {'CH4': 3.0, 'O2': 0.5},
        'product_amounts': {'CO2': 27.4, 'H2O': 22.5},
        'product_prices': {'CO2': 0.1, 'H2O': 0.05},
        'yield_factor': 0.95,
        'electricity_price': 0.8,
        'labor_cost': 500,
        'equipment_depreciation': 200,
        'equipment_investment': 100000,
        'annual_batches': 300
    }

    # 综合评估
    result = validator.comprehensive_evaluation(equation, reaction_data, production_scale=100)

    print(result['summary'])
    print("\n【优化建议】:")
    for i, rec in enumerate(result['recommendations'], 1):
        print(f"  {i}. {rec}")


if __name__ == "__main__":
    main()

